package com.atguigu.gmall.seckill.listener;
import java.math.BigDecimal;

import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.enums.OrderStatus;
import com.atguigu.gmall.feign.product.SkuDetailFeignClient;
import com.atguigu.gmall.order.entity.OrderDetail;
import com.atguigu.gmall.product.entity.SkuInfo;
import com.google.common.collect.Lists;

import java.util.Arrays;
import java.util.Date;

import com.atguigu.gmall.cache.util.Jsons;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.order.entity.OrderInfo;
import com.atguigu.gmall.seckill.entity.SeckillGoods;
import com.atguigu.gmall.seckill.service.SeckillBizService;
import com.atguigu.gmall.seckill.service.SeckillGoodsService;
import com.atguigu.gmall.seckill.to.SeckillQueueMsg;
import com.atguigu.gmall.util.consts.MqConst;
import com.atguigu.gmall.util.service.RabbitService;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.UUID;

/**
 * @author lfy
 * @Description 监听秒杀排队的数据
 * @create 2022-10-25 14:36
 */
@Slf4j
@Service
public class SeckillQueueListener {

    @Autowired
    RabbitService rabbitService;

    @Autowired
    SeckillBizService seckillBizService;

    @Autowired
    StringRedisTemplate redisTemplate;


    @Autowired
    SeckillGoodsService seckillGoodsService;

    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue(value = MqConst.SECKILL_QUEUE_QUEUE,durable = "true",exclusive = "false",autoDelete = "false"),
                    exchange = @Exchange(value = MqConst.SECKILL_EVENT_EXCHANGE),
                    key = MqConst.RK_SECKILL_QUEUE
            )
    })
    public void seckillQueue(Message message, Channel channel) throws IOException {

        long tag = message.getMessageProperties().getDeliveryTag();
        String json = new String(message.getBody());

        String orderKey = "";

        try {

            //TODO 秒杀排队
            log.info("监听到排队的秒杀请求，正在后台处理为他生成秒杀的订单");
            SeckillQueueMsg queueMsg = Jsons.toObj(json, SeckillQueueMsg.class);
            Long skuId = queueMsg.getSkuId();
            //1、redis、内存状态位已经扣除
            orderKey = RedisConst.SECKILL_ORDER + queueMsg.getSeckillCode();

            //2、直接扣除数据库库存。
            seckillGoodsService.deduceStock(skuId,1); //违反非负约束

            //3、生成订单，缓存到redis
            OrderInfo orderInfo = prepareOrderInfo(queueMsg);
            redisTemplate.opsForValue().set(orderKey,Jsons.toStr(orderInfo));

            String formatDate = DateUtil.formatDate(new Date());
            //4、更新redis中每个商品的库存【页面展示的是商品的库存】
            String goodJson = redisTemplate.opsForHash()
                    .get(RedisConst.SECKILL_GOOD_KEY + formatDate, skuId.toString()).toString();
            SeckillGoods seckillGoods = Jsons.toObj(goodJson, SeckillGoods.class);
            //5、拿到redis的实时库存；seckill:good:stockcount:2022-10-25:49
            String num = redisTemplate.opsForValue().get(RedisConst.SECKILL_GOOD_STOCK + formatDate + ":" + skuId);
            //同步最新库存
            seckillGoods.setStockCount(Integer.parseInt(num));
            //修改redis中的商品数据
            redisTemplate.opsForHash()
                    .put(RedisConst.SECKILL_GOOD_KEY + formatDate,
                    skuId.toString(),Jsons.toStr(seckillGoods));

            channel.basicAck(tag,false);
        }catch (Exception e){
            //库存扣减失败
            redisTemplate.opsForValue().set(orderKey,RedisConst.SECKILL_ORDER_NO_STOCK);
            //3、库存扣不了。redis中订单就是 NO
            channel.basicAck(tag,false);
        }

    }



    private OrderInfo prepareOrderInfo(SeckillQueueMsg queueMsg) {
        OrderInfo orderInfo = new OrderInfo();
        Long skuId = queueMsg.getSkuId();
        SeckillGoods goodsDetail = seckillBizService.getGoodsDetail(skuId);
        orderInfo.setTotalAmount(goodsDetail.getCostPrice());
        orderInfo.setUserId(queueMsg.getUserId());
        orderInfo.setOutTradeNo(UUID.randomUUID().toString().replace("-",""));
        orderInfo.setTradeBody(goodsDetail.getSkuName());
        orderInfo.setActivityReduceAmount(goodsDetail.getPrice().subtract(goodsDetail.getCostPrice()));
        orderInfo.setCouponAmount(new BigDecimal("0"));
        orderInfo.setOriginalTotalAmount(new BigDecimal("0"));
        orderInfo.setFeightFee(new BigDecimal("0"));
        orderInfo.setRefundableTime(new Date());

        //这个订单买了哪些商品。订单明细
        OrderDetail orderDetail = new OrderDetail();

        orderDetail.setSkuId(skuId);
        orderDetail.setUserId(orderInfo.getUserId());
        orderDetail.setSkuName(goodsDetail.getSkuName());
        orderDetail.setImgUrl(goodsDetail.getSkuDefaultImg());
        orderDetail.setOrderPrice(goodsDetail.getPrice()); //原价
        orderDetail.setSkuNum(1);
        orderDetail.setCreateTime(new Date());
        orderDetail.setSplitTotalAmount(goodsDetail.getCostPrice());
        orderDetail.setSplitActivityAmount(goodsDetail.getPrice().subtract(goodsDetail.getCostPrice()));
        orderDetail.setSplitCouponAmount(new BigDecimal("0"));


        orderInfo.setOrderDetailList(Arrays.asList(orderDetail));

        return orderInfo;
    }
}
